package org.visionlibrary.image.filters.thresholding;

import java.awt.Point;

import javax.media.jai.TiledImage;

import org.visionlibrary.image.model.WindowFilter;


/* Niblack recommends K_VALUE = -0.2 for images with black foreground 
*  objects, and K_VALUE = +0.2 for images with white foreground objects.
*  
*  Niblack W. (1986) "An introduction to Digital Image Processing" Prentice-Hall
*/
public class SimpleNiblackThreshold extends WindowFilter {
	protected int width = 9;
	protected int height = 9;
	protected double k = -0.2; //recomended for black foreground
	
	protected int foreground = 255; //foreground pixel value (default 0)
	protected int background = 0; //background pixel value (default 255 for 8bpc image)
	
	public SimpleNiblackThreshold() {
		this(9,9,-0.2);
	}
	
	public SimpleNiblackThreshold(int width, int height, double k) {
		this.width = width;
		this.height = height;
		this.k = k;
	}
	
	public SimpleNiblackThreshold(int width, int height, double k, int foreground,
			int background) {
		this.width = width;
		this.height = height;
		this.k = k;
		this.foreground = foreground;
		this.background = background;
	}

	@Override
	protected int getNewPixelVal(TiledImage src, Point p, int channel) {
		int sum = 0, sum_sqr = 0; //temp variables used in the calculation of local mean and variances
		double local_mean=0;	     //gray level mean in a particular window position
		double local_var=0;		 //gray level variance in a particular window position */

		//used per channel model in library but if filter will be used only for gray scale images
		//it wont be a problem, 
		//count sum of pixel values and sum of squares
		Point pIter = new Point();
		for (pIter.y = 0; pIter.y < windowHeight; pIter.y++)
			for (pIter.x = 0; pIter.x < windowWidth; pIter.x++) {
				int val = getWindowPixelVal(src, pIter, channel);
				sum += val;
				sum_sqr += val * val;
			}
		
		//count local mean (for desired window)
		local_mean = (double)sum /(double)(windowHeight*windowWidth);
		//System.out.println("local_mean = " + local_mean);
		//count local variance 
	    local_var = ((double)sum_sqr/(double)(windowHeight*windowWidth)) - local_mean*local_mean;
	    //System.out.println("local_var = " + local_var);

	    //count local threshold
	    double threshold = local_mean + k*Math.sqrt(local_var);
	    //System.out.println("threshold = " + threshold);
	    
	    //return proper values
	    return ((getWindowPixelVal(src, dstPointInWindow, channel) > threshold ) ? foreground : background);
	}

	@Override
	protected void setWindowProperties() {
		windowWidth = width;
		windowHeight = height;
		dstPointInWindow = new Point(width / 2, height / 2);
	}
}
